package bosVM2.meta.Objects;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

import bosVM2.FaultHandling.StringEncoderDecoder;
import bosVM2.util.Map;

public class BosClass {
	
	StringEncoderDecoder ham = new StringEncoderDecoder();
	
	//
	private String cname;
	private Map<String, BosMethod> methods;
	private Map<String, BosField> fields;
	private BosClass _super;
	
	//util: Contructor and toString
	
	public BosClass(String name, BosClass _super)
	{ 
		setClassName(name);
		methods = new Map<String, BosMethod>();
		fields = new Map<String, BosField>();
		if(_super == null)
		{ 
			this._super = null; 
		}
		else 
		{ 
			this._super = _super; 
		}
		 
	}
	
	//ClassName
	public String getClassName() {
		Object[] temp = ham.deCode(cname);
		if((boolean) temp[0]) {
			cname = ham.enCode((String) temp[1]);
		}
		return (String) temp[1];
	}
	
	public void setClassName(String s)
	{
		cname = ham.enCode(s);
	}
	
	//Method and field maps
	//Getters
	public BosMethod getMethod(String b) {
		String name = ham.enCode(b);
		BosMethod out = methods.get(name);
		if(out == null) {
			if(methodsMapKeyErrorCheckAndCorrection()) {
				out = methods.get(name);
			} else { return null; } //TODO cast internal exception?
		}
		return out;
	}
	
	public BosField getField(String b) {
		String name = ham.enCode(b);
		BosField out = fields.get(name);
		if(out == null) {
			if(fieldsMapKeyErrorCheckAndCorrection()) {
				out = fields.get(name);
			} else { return null; } //TODO cast internal exception?
		}
		return out;
	}
	
	//Setters
	public void putMethod(BosMethod m) {
		String name = ham.enCode(m.getName());
		methods.put(name, m);
	}

	public void putField(BosField f) {
		String name = ham.enCode(f.getName());
		fields.put(name, f);
	}
	
	public Set<String> getMethods()
	{
		HashSet<String> out = new HashSet<String>();
		for(String s: methods.getKeys()) {
			out.add((String) ham.deCode(s)[1]);
		}
		return out;
	}
	
	public Set<String> getFields()
	{
		HashSet<String> out = new HashSet<String>();
		for(String s: fields.getKeys()) {
			out.add((String) ham.deCode(s)[1]);
		}
		return out;
	}
	
	public String toString() {
		return "class: "+ham.deCode(cname)[1]+ " methods: " + methods + " Fields: " + fields;
	}
	
	/*
	 * Copy paste solution, make generic fault handler if time permits, and when the simple ones work;-)
	 */
	//Fields error correction
	private void fieldsMapKeyErrorCorrection(Object[] errorArray) {
		fields.replaceKey((String) errorArray[2], ham.enCode((String) errorArray[1])); 
	}
	/*
	 * A function for finding and correction error in the keys of the classes map.
	 * @return true if an error has been found and corrected, false if not.
	 */
	private boolean fieldsMapKeyErrorCheckAndCorrection() {
		ArrayList<Object[]> error = null;
		for(String s: fields.getKeys()) {
			Object[] temp = ham.deCode(s);
			if((boolean) temp[0]) {
				if(error == null) {
						error = new ArrayList<Object[]>();
					}
				error.add(temp);
			}
		}
		if(error != null) {
			for(Object[] o: error) {
				fieldsMapKeyErrorCorrection(o);
			}
			return true;
		} else { return false; }
	}
	
	//Methods error correction
	private void methodsMapKeyErrorCorrection(Object[] errorArray) {
		fields.replaceKey((String) errorArray[2], ham.enCode((String) errorArray[1])); 
	}
	/*
	 * A function for finding and correction error in the keys of the classes map.
	 * @return true if an error has been found and corrected, false if not.
	 */
	private boolean methodsMapKeyErrorCheckAndCorrection() {
		ArrayList<Object[]> error = null;
		for(String s: methods.getKeys()) {
			Object[] temp = ham.deCode(s);
			if((boolean) temp[0]) {
				if(error == null) {
						error = new ArrayList<Object[]>();
					}
				error.add(temp);
			}
		}
		if(error != null) {
			for(Object[] o: error) {
				methodsMapKeyErrorCorrection(o);
			}
			return true;
		} else { return false; }
	}
	//util
	
	public String getClassNameI()
	{
		return cname;
	}
	
	public void setClassNameI(String s)
	{
		cname = s;
	}
}
